home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 06 - 1990 / 06.07 Jul 90 / Printing Primer ƒ / ReportUtils.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-21  |  18.1 KB  |  928 lines  |  [TEXT/KAHL]

  1. /*******************************************\
  2. *    file:         ReportUtils.c                *
  3. *    version:    1.0ß                        *
  4. *                                            *
  5. *    Common routines for printing reports    *
  6. *                                            *
  7. * -----------------------------------------    *
  8. * By:    Donald Koscheka                        *
  9. * Date:    30-OCT-89                            *
  10. * ©    Copyright 1989, Donald Koscheka            *
  11. *    All Rights Reserved                        *
  12. *                                            *
  13. * -----------------------------------------    *
  14. \*******************************************/
  15.  
  16. #include <MacTypes.h>
  17. #include <MemoryMgr.h>
  18. #include <ResourceMgr.h>
  19. #include <OSUtil.h>
  20. #include <HyperXCmd.h>
  21. #include <HyperUtils.h>
  22. #include <PrintMgr.h>
  23. #include <ReportUtils.h>
  24.  
  25.                 /****************************************************/
  26.                 /*             --- MISCELLANEOUS UTILITIES ---            */
  27.                 /*                                                    */
  28.                 /****************************************************/
  29.                 
  30. short    getStringHandleSize( h )
  31.         Handle    h;
  32. /******************************
  33. * In hypercard, strings are padded
  34. * out to even boundaries so that the
  35. * handle size may be longer than
  36. * you'd like.
  37. * This routine returns the length
  38. * of the string up to but not 
  39. * including the NULL
  40. *
  41. * This routine is to be used for 
  42. * NULL terminated strings only!
  43. *
  44. *******************************/
  45. {
  46.     short    i    = 0;
  47.     char    *endPoint;
  48.     
  49.     if( validHandle( h ) ){
  50.         i = (short)GetHandleSize( h );
  51.     
  52.         endPoint = *h + i - 1;
  53.         while( *endPoint ){
  54.             --i;
  55.             --endPoint;
  56.         }
  57.     }
  58.     return( i );
  59. }
  60.  
  61.  
  62.  
  63. short    strNComp( s1, s2, len )
  64.     char    *s1;
  65.     char    *s2;
  66.     long    len;
  67. /******************************
  68. *
  69. ******************************/
  70. {
  71.     short    indx;
  72.     short    match = 1;
  73.     
  74.     for( indx = 1; indx <= len; indx++ )
  75.         if( *s1++ != *s2++ ){
  76.             match = 0;
  77.             break;
  78.         }
  79.     return( match );
  80. }
  81.  
  82.                 /****************************************************/
  83.                 /*             --- PARSING ROUTINES ---                */
  84.                 /*                                                    */
  85.                 /****************************************************/
  86.  
  87.  
  88. long matchToken( buf, tabl )
  89.     Handle    buf;
  90.     short    tabl;
  91. /******************************
  92. * given an input buffer and the resource 
  93. * id of the parse table, return 
  94. * the token that represents the input
  95. * string.
  96. *
  97. * A token of 0 is returned if no
  98. * match is found.  This way, you
  99. * can use the first item in the list
  100. * as the default item!
  101. *
  102. * The symbol table should have the 
  103. * format:
  104. *
  105. *    <string>, <token>
  106. * where string mathces to the input
  107. * string and token is that value for 
  108. * a given match.
  109. ******************************/
  110. {
  111.     char    *bp;            /*** pointer to input strings            ***/
  112.     char    *tp;
  113.     Handle    strH;            /*** handle to parse strings resource    ***/
  114.     long    token     = 0;    /*** return the default if no match        ***/
  115.     short    indx    = 0;
  116.     short    theID;
  117.     ResType    theType;    
  118.     short    done = 0;
  119.     long    len;
  120.     char    theNum[31];    
  121.     char    *np;
  122.     char    theName[256];
  123.     char    theString[256];
  124.         
  125.     bp = *buf;
  126.     
  127.     tp = bp;
  128.     while( *tp ){
  129.         toupper( *tp );
  130.         tp++;
  131.     }
  132.     
  133.     strH     = GetResource( STRING_TYPE, tabl );
  134.     
  135.     if( strH ){
  136.         
  137.         GetResInfo( strH, &theID, &theType, &theName );
  138.         
  139.         /*** compare the string to the allowable tokens ***/
  140.         indx    = 1 ;
  141.         
  142.         while( !done ){
  143.             theString[0] = '\0';
  144.             GetIndString( &theString, tabl, indx );
  145.             
  146.             if( theString[0] == '\0' )    /* no strings matched the input     */
  147.                 done = 1;
  148.             else{                        /* attempt to match to current str    */
  149.                 
  150.                 PtoCstr( (char *)&theString );
  151.                 
  152.                 len = 0;
  153.                 
  154.                 bp = theString;
  155.                 while ( *bp != ',' ){
  156.                     bp++;
  157.                     len++;
  158.                 }
  159.             
  160.                 if( strncmp( *buf, (char *)theString, len ) == 0){
  161.                     /* have a match so extract the token    */                    
  162.                     
  163.                     /*** move past any garbage in the string ***/
  164.                     while( (*bp < '0' || *bp > '9') && *bp != '-')
  165.                         bp++;
  166.                     
  167.                     /*** now copy what bp points to into a     ***/
  168.                     /*** a pascal style string                ***/
  169.                     
  170.                     theNum[0] = '\0';
  171.                     np = &theNum[1];
  172.                     
  173.                     while( *bp >= '0' && *bp <= '9' ){
  174.                         theNum[0]++;
  175.                         *np++ = *bp++;
  176.                     }
  177.                     
  178.                     /*** np is a valid p-string                ***/
  179.                     StringToNum( theNum, &token );
  180.                     done = 1;
  181.                 }
  182.                 else
  183.                     indx++;
  184.             }
  185.         }
  186.     }
  187.     
  188.     return( token );
  189. }
  190.  
  191.  
  192. long    parseNum( bp )
  193.             char    *bp;
  194. /******************************
  195. * parse the data stream 
  196. * and return a numeric 
  197. * value.  The stream is null
  198. * terminated.
  199. *
  200. ******************************/
  201. {
  202.     long    num = 0;
  203.     
  204.     char    theString[256];
  205.     short    done = 0;
  206.     char    *ps;
  207.         
  208.     /*** move the input pointer until we're looking at a number    ***/
  209.     while( *bp && ( *bp < '0' || *bp > '9' ) && *bp != '-' )
  210.         bp++;
  211.     
  212.     /*** copy the data into a pascal string     ***/
  213.     ps    = theString;
  214.     ps++;
  215.     
  216.     while( *bp >= '0' && *bp <= '9' )
  217.         *ps++ = *bp++;
  218.     
  219.     /*** moved one past the output so try this    ***/
  220.     theString[0] = (char)( ps - theString -1  );    
  221.     StringToNum( theString, &num );
  222.     
  223.     return( num );    
  224. }
  225.  
  226.  
  227.  
  228. char    *nextToken( bp )
  229.             char    *bp;
  230. /******************************
  231. * given a pointer to an
  232. * input stream, move to the 
  233. * next token in the stream. 
  234. * Token's are delineated by
  235. * ',' or whitespace
  236. *
  237. * Assumes we are pointing to the current token
  238. * Move past the current token and the white
  239. * space that follows it.
  240. ******************************/
  241. {
  242.     /*** move past the current token    ***/
  243.     while( *bp &&(*bp != ',' && *bp != SPACE && *bp != CR && *bp != LF && *bp != TAB) )
  244.         bp++;
  245.  
  246.     /*** move past the white space to the next token    ***/
  247.     while( *bp == ',' || *bp == SPACE || *bp == CR || *bp == LF || *bp == TAB )
  248.         bp++;
  249.     
  250.     return( bp );
  251. }
  252.  
  253.  
  254.  
  255. void     parseRect( buf, theRect )
  256.             Handle    buf;
  257.             Rect    *theRect;
  258. /******************************
  259. * parse the data stream 
  260. * into a rectangle
  261. ******************************/
  262. {
  263.     char    *bp;
  264.     
  265.     HLock( buf );
  266.     
  267.     bp = *buf;
  268.     theRect->top = parseNum( bp );
  269.     bp    = nextToken( bp );
  270.     
  271.     theRect->left = parseNum( bp );
  272.     bp    = nextToken( bp );
  273.     
  274.     theRect->bottom = parseNum( bp );
  275.     bp    = nextToken( bp );
  276.     
  277.     theRect->right = parseNum( bp );
  278.     bp    = nextToken( bp );
  279.     
  280.     HUnlock( buf );
  281. }
  282.  
  283.  
  284.  
  285. void    CopyRect( r1, r2 )
  286.         Rect    *r1;
  287.         Rect    *r2;
  288. /****************************
  289. * copy rectangle r1 to r2
  290. *
  291. ****************************/
  292. {
  293.     r2->top     = r1->top;
  294.     r2->left     = r1->left;
  295.     r2->bottom     = r1->bottom;
  296.     r2->right    = r1->right;
  297. }
  298.  
  299.  
  300.     
  301.                 /****************************************************/
  302.                 /*                 --- PRINTING UTILITIES ---            */
  303.                 /*                                                    */
  304.                 /****************************************************/
  305.  
  306.  
  307.  
  308.  
  309.  
  310.  
  311.  
  312. void    FootNotePage( pp )
  313.         pInfoPtr    pp;
  314. /******************************
  315. * draw the footnote for this page
  316. ******************************/
  317. {
  318.     Handle        theText;
  319.     footPtr        myFoot;
  320.     short        siz;
  321.     FontInfo    fInfo;
  322.     short        hite;
  323.     GrafPtr        oldPort;
  324.     styleSet    footStyle;
  325.     char        thePage[32];
  326.     char        theNum[32];
  327.     Rect        temp;
  328.         
  329.     if( pp->footNote.hite ){
  330.         CopyRect( &(pp->margin), &temp );
  331.  
  332.         SetMargin( pp, 0, 0, 0 ,0 );
  333.         
  334.         GetPort( &oldPort );
  335.         SetPort( (GrafPtr)(pp->prPort) );
  336.     
  337.         PenNormal();
  338.     
  339.         footStyle.Font = TIMES;
  340.         footStyle.Size = 12;
  341.         footStyle.Style= PLAIN_TEXT;
  342.         footStyle.Just = teJustLeft;
  343.         
  344.         SetFontStyles( pp, (stylePtr)&footStyle );
  345.         
  346.         GetFontInfo( &fInfo );
  347.         hite     = fInfo.ascent + fInfo.descent + fInfo.leading;
  348.     
  349.         /*** draw the company name and the version number ***/
  350.         if( theText = pp->footNote.key1 ){
  351.             MoveTo( pp->margin.left, pp->margin.bottom+(2*hite)-4 );
  352.             siz = getStringHandleSize( theText );
  353.     
  354.             HLock( theText );        
  355.             DrawTextRun( pp, *theText, siz, teJustLeft );    
  356.             HUnlock( theText );
  357.         }
  358.     
  359.         if( theText = pp->footNote.key2 ){
  360.             MoveTo( pp->margin.left, pp->margin.bottom+(2*hite)-4);
  361.             siz = getStringHandleSize( theText );
  362.     
  363.             HLock( theText );        
  364.             DrawTextRun( pp, *theText, siz, teJustRight );    
  365.             HUnlock( theText );
  366.         }
  367.         
  368.         /*** draw the date and the page number                ***/
  369.         if( theText = pp->footNote.key3 ){
  370.             MoveTo( pp->margin.left, pp->margin.bottom+(3*hite)-4);
  371.             siz = getStringHandleSize( theText );
  372.     
  373.             HLock( theText );        
  374.             DrawTextRun( pp, *theText, siz, teJustLeft );    
  375.             HUnlock( theText );
  376.         }
  377.     
  378.         if( pp->pagecount ){
  379.             thePage[0] = '\0';
  380.             MoveTo( pp->margin.left, pp->margin.bottom+(3*hite)-4);
  381.             strcat( thePage, "Page #");
  382.             NumToString( (long)pp->pagecount, theNum );
  383.             
  384.             PtoCstr( (char *)&theNum );
  385.             strcat( thePage, theNum );
  386.             DrawTextRun( pp, thePage, strlen( thePage ), teJustRight );
  387.         }
  388.  
  389.         CopyRect( &temp, &(pp->margin) );
  390.         SetFontStyles( pp, (stylePtr)&(pp->defaultStyle) );
  391.         SetPort( oldPort );
  392.     }
  393. }
  394.  
  395.  
  396.  
  397. void    EjectPage( pp )
  398.         pInfoPtr    pp;
  399. /******************************
  400. * Eject the current page and 
  401. * adjust the rectangle 
  402. * accordingly
  403. *
  404. ******************************/
  405. {
  406.  
  407.     FootNotePage( pp );
  408.     
  409.     PrClosePage( pp->prPort );
  410.     
  411.     pp->pagecount++;
  412.     pp->totalpages++;
  413.     
  414.     if( pp->totalpages == 128 ){
  415.         TPPrPort    tp;
  416.         PrCloseDoc( pp->prPort );
  417.         
  418.         tp = PrOpenDoc( pp->prRecHandle, NIL, NIL );
  419.         pp->prPort = (GrafPtr)tp;
  420.         pp->totalpages = 0;
  421.         SetPort( (GrafPtr)tp );
  422.     }
  423.     
  424.     PrOpenPage( pp->prPort, NIL );
  425.  
  426.     pp->curntPen.h = pp->margin.left;
  427.     pp->curntPen.v = pp->margin.top;
  428. }
  429.  
  430.  
  431. void     NewLine( pp, y )
  432.         pInfoPtr    pp;
  433.         short        y;
  434. /******************************
  435. * Move to a new position on the
  436. * page checking for page break.
  437. ******************************/
  438. {
  439.     CheckPageBreak( pp, y );
  440.     pp->curntPen.h = pp->margin.left;
  441.     pp->curntPen.v += y;
  442.     MoveTo( pp->curntPen.h, pp->curntPen.v );
  443. }
  444.  
  445.  
  446. void    CheckPageBreak( pp, y )
  447.         pInfoPtr    pp;
  448.         short        y;
  449. /******************************
  450. * Check to see if the current line
  451. * will fit on the page, break the 
  452. * page if not.
  453. *
  454. * This routine manages the pen 
  455. * updating.
  456. *
  457. * √ 10.31.89
  458. ******************************/
  459. {
  460.     if( (pp->curntPen.v + y) >= pp->margin.bottom ){
  461.         EjectPage( pp );
  462.         NewLine( pp, y );
  463.     }    
  464.         
  465.     /* pp->curntPen.v += y; */
  466. }
  467.  
  468.  
  469.  
  470.  
  471.  
  472.     
  473.                 /****************************************************/
  474.                 /*                 --- PORT UTILITIES ---                */
  475.                 /*                                                    */
  476.                 /****************************************************/
  477.  
  478.  
  479.  
  480. void SetMargin( pp, t, l, b, r )
  481.         pInfoPtr    pp;
  482.         short        t;
  483.         short        l;
  484.         short        b;
  485.         short        r;
  486. /******************************
  487. * Reset the margin rectangle in
  488. * the printing rect.
  489. *
  490. * We add to top left and subtract
  491. * from bottom right.
  492. *
  493. * if no parameters specified, then
  494. * set the margin to the page margin.
  495. *
  496. * 11.7.89 adjust bottom margin for
  497. *             footer hite 
  498. ******************************/
  499. {
  500.     register    TPPrint        tp = *(pp->prRecHandle);
  501.     
  502.     pp->margin.top         = tp->prInfo.rPage.top + t;
  503.     pp->margin.left        = tp->prInfo.rPage.left + l;
  504.     pp->margin.bottom    = tp->prInfo.rPage.bottom - b - pp->footNote.hite;
  505.     pp->margin.right    = tp->prInfo.rPage.right - r;
  506. }
  507.  
  508.  
  509.  
  510. void     SetFont( sp, theFont )
  511.         stylePtr    sp;
  512.         short        theFont;
  513. /*******************************
  514. * Reset the font for this document
  515. *******************************/
  516. {
  517.     if( theFont )
  518.         sp->Font = theFont;
  519.     else
  520.         sp->Font = DEFAULT_FONT;
  521. }
  522.  
  523.  
  524.  
  525. void     SetFontSize( sp, theSize )
  526.         stylePtr    sp;
  527.         short        theSize;
  528. /*******************************
  529. * Set the font size for this document
  530. *******************************/
  531. {
  532.     if( theSize )
  533.         sp->Size = theSize;
  534.     else
  535.         sp->Font = DEFAULT_SIZE;
  536. }
  537.  
  538.  
  539.  
  540. void     SetFontStyle( sp, theStyle )
  541.         stylePtr    sp;
  542.         short        theStyle;
  543. /*******************************
  544. * Style is cumulative.  To reset it
  545. * you must set it to plain text.
  546. *******************************/
  547. {
  548.     if( theStyle )
  549.         sp->Style &= theStyle;
  550.     else
  551.         sp->Style = PLAIN_TEXT;
  552. }
  553.  
  554.  
  555.  
  556. void     SetFontJust( sp, theJust )
  557.         stylePtr    sp;
  558.         short        theJust;
  559. /*******************************
  560. *
  561. *******************************/
  562. {
  563.  
  564.     if( theJust )
  565.         sp->Just = theJust;
  566.     else
  567.         sp->Just = teJustLeft;
  568. }
  569.  
  570.  
  571.  
  572. void     SetFontStyles(  pp, sp )
  573.         pInfoPtr    pp;
  574.         stylePtr    sp;
  575. /*******************************
  576. * facilitation piece.  requires some
  577. * thinking yet (not fully happy with
  578. * the data abstractions I've developed
  579. * to this point-- 11.1.89)
  580. *******************************/
  581. {
  582.     GrafPtr        oldPort;
  583.     
  584.     GetPort( &oldPort );
  585.     SetPort( (GrafPtr)(pp->prPort) );
  586.     
  587.     TextFont( sp->Font );
  588.     TextSize( sp->Size );    
  589.     TextFace( sp->Style );
  590.     
  591.     SetPort( oldPort );
  592. }
  593.  
  594.  
  595.  
  596. void    DrawTextRun( pp, tx, len, just )
  597.         pInfoPtr    pp;
  598.         char        *tx;
  599.         short        len;
  600.         short        just;
  601. /**********************************
  602. * Draw the given run of text taking
  603. * without breaking the page.
  604. **********************************/
  605. {
  606.     short    pagewidth    = pp->margin.right - pp->margin.left;
  607.     short    twidth;
  608.     
  609.     /*** need to know the pixel width of the line ***/
  610.     twidth = TextWidth( tx, 0, len );
  611.     
  612.     switch( just ){
  613.         case teJustLeft:
  614.                 break;
  615.                 
  616.         case teJustRight:
  617.                 Move( (pagewidth - twidth), 0 );
  618.                 break;
  619.                 
  620.         case teJustCenter:
  621.                 Move( (pagewidth - twidth)/2, 0 );
  622.                 break;
  623.                 
  624.         case teJustFill:
  625.                 /*** doesn't do anything yet ***/
  626.                 break;
  627.     }/* switch */
  628.     
  629.     DrawText( tx, 0, len );    
  630. }
  631.  
  632.  
  633.  
  634. void     PrintString( pp, theText, hite )
  635.         pInfoPtr    pp;
  636.         Handle        theText;
  637.         short        hite;
  638. /*******************************
  639. * draw the text object passed in
  640. * as a parameter.
  641. *
  642. * titles are always followed by
  643. * blank lines so double the hite 
  644. *******************************/
  645. {
  646.     short        siz;
  647.     FontInfo    fInfo;
  648.  
  649.     NewLine( pp, hite );
  650.     siz = getStringHandleSize( theText );
  651.     DrawTextRun( pp, *theText, siz, teJustLeft );    
  652.     NewLine( pp, hite );
  653.     SetFontStyles( pp, (stylePtr)&(pp->defaultStyle) );
  654. }
  655.  
  656.  
  657.  
  658.  
  659. void    DrawTextLine( pp, tx, len, hite, just )
  660.         pInfoPtr    pp;
  661.         char        *tx;
  662.         short        len;
  663.         short        hite;
  664.         short        just;
  665. /**********************************
  666. * Draw the given run of text taking
  667. * into account page breaks if necessary.
  668. *
  669. * handles justification for the line.
  670. *
  671. * A line is defined as having constant
  672. * vertical position so we only have to move
  673. * the pen horizontally on a line to fit
  674. * it into the correct format.
  675. **********************************/
  676. {
  677.     NewLine( pp, hite );
  678.     DrawTextRun( pp, tx, len, just );
  679. }
  680.  
  681.  
  682.  
  683. void DrawLeftMargin( pp, theLeft, hite )
  684.         pInfoPtr    pp;
  685.         Handle        theLeft;
  686.         short        hite;
  687. /*******************************
  688. * Margins and style are set before
  689. * calling this routine.
  690. *
  691. * EXPERIMENTAL ROUTINE.
  692. *******************************/
  693. {
  694.     Rect        temp;
  695.     
  696.     /*** Draw the labels and answer portions ***/
  697.     if( theLeft && (GetHandleSize( theLeft )) ){
  698.         CopyRect( &(pp->margin), &temp );
  699.         
  700.         pp->margin.right = temp.left - 12;
  701.         MoveTo( pp->margin.left, pp->curntPen.v );
  702.     
  703.         HLock( theLeft );
  704.         DrawTextRun( pp, *theLeft, getStringHandleSize(theLeft ), teJustRight );
  705.         HUnlock( theLeft );
  706.         
  707.         CopyRect( &temp, &(pp->margin) );
  708.         
  709.         SetHandleSize( theLeft, 0L );
  710.     }
  711. }
  712.  
  713.  
  714.  
  715. void DrawRightMargin( pp, theRight, hite )
  716.         pInfoPtr    pp;
  717.         Handle        theRight;
  718.         short        hite;
  719. /*******************************
  720. * the answer gets printed "in the 
  721. * margin"
  722. *
  723. * EXPERIMENTAL ROUTINE.
  724. *******************************/
  725. {
  726.     Rect        temp;
  727.     register    TPPrint        tp = *(pp->prRecHandle);
  728.     
  729.     /*** Draw the labels and answer portions ***/
  730.     if( theRight && (GetHandleSize( theRight )) ){
  731.         CopyRect( &(pp->margin), &temp );
  732.         
  733.         pp->margin.left = pp->margin.right + 30;
  734.         pp->margin.right= tp->prInfo.rPage.right;
  735.         MoveTo( pp->margin.left, pp->curntPen.v  );
  736.         
  737.         HLock( theRight);
  738.         DrawTextRun( pp, *theRight, getStringHandleSize(theRight), teJustLeft  );
  739.         HUnlock( theRight);
  740.         MoveTo( pp->curntPen.h, pp->curntPen.v );
  741.         
  742.         CopyRect( &temp, &(pp->margin) );
  743.         
  744.         SetHandleSize( theRight, 0L );
  745.     }
  746. }
  747.  
  748.  
  749.  
  750. char    *EndOfWord( wPtr, hardline )
  751.         char    *wPtr;
  752.         short    *hardline;
  753. /******************************
  754. * Given a pointer to a  word, calculate the 
  755. * length of the next word in the run. The length
  756. * is determined by adding the width  of each
  757. * character together until a word break.
  758. *
  759. * The difference between tpos and wpos is always
  760. * one word (including the sticky characters)
  761. *
  762. * IN: Pointer to text 
  763. *    wPtr == pointer to NEXT word in
  764. *    run (or NIL if No next word)
  765. *
  766. * adjusts the output ptr which will
  767. * be pointing to the word break character.
  768. *
  769. * first occurrance of space is considered
  770. * part of the word.
  771. ******************************/
  772. {    
  773.     *hardline = 0;
  774.     
  775.     while( 1 ){
  776.         switch( (short)*wPtr ){
  777.             case NULL:
  778.                     return( wPtr );
  779.                     break;
  780.                     
  781.             case QUOTE:
  782.             case COMMA:
  783.             case PERIOD:            
  784.             case TAB:
  785.             case SPACE:
  786.             case ';':
  787.             case '!':
  788.             case '?':
  789.                     ++wPtr;        
  790.                     return( wPtr );
  791.                     break;
  792.                     
  793.             case CR:
  794.             case FF:
  795.                     ++wPtr;
  796.                     *hardline = 1;
  797.                     return( wPtr );
  798.                         break;    
  799.                         
  800.             default:
  801.                     ++wPtr;
  802.                     break;
  803.         }/*** switch( *wPtr ) ****/
  804.     }/*** while(1) ****/
  805. }
  806.  
  807.  
  808.  
  809. void    FlushLine( pp, lineStart, len, just, theLeft, theRight, hite )
  810.         pInfoPtr    pp;
  811.         char        *lineStart;
  812.         short        len;
  813.         short        just;
  814.         Handle        theLeft;
  815.         Handle        theRight;
  816.         short        hite;
  817. /*******************************
  818. * Flush the current line out to 
  819. * the printer.
  820. *
  821. *******************************/
  822. {
  823.     if( len ){
  824.         CheckPageBreak( pp, hite );
  825.         NewLine( pp, hite );
  826.         DrawLeftMargin( pp, theLeft, hite );
  827.         DrawRightMargin( pp, theRight, hite );
  828.         DrawTextRun( pp, lineStart, len, just );
  829.     }
  830. }
  831.  
  832.  
  833.  
  834.  
  835. void     DrawParagraph( pp, theText, theLeft, theRight )
  836.         pInfoPtr    pp;
  837.         Handle        theText;
  838.         Handle        theLeft;
  839.         Handle        theRight;
  840. /*******************************
  841. * Draw the text.  In effect, theLeft
  842. * is the text to the left of the 
  843. * paragraph and theRight is text
  844. * to the right of the paragraph.
  845. *
  846. * Margins and style are set before
  847. * calling this routine.
  848. *
  849. * EXPERIMENTAL ROUTINE.
  850. *******************************/
  851. {
  852.     short        siz;
  853.     FontInfo    fInfo;
  854.     short        hite;
  855.     GrafPtr        oldPort;
  856.     char        *lineStart;
  857.     char        *lineEnd;
  858.     char        *nextWord;
  859.     short        lineWidth    = 0;
  860.     short        wordWidth    = 0;
  861.     short        theMargin;
  862.     short        just;
  863.     short        hardline;
  864.     short        wid;
  865.     
  866.     GetPort( &oldPort );
  867.     SetPort( (GrafPtr)(pp->prPort) );
  868.  
  869.     GetFontInfo( &fInfo );
  870.     hite    = fInfo.ascent + fInfo.descent + fInfo.leading;
  871.     
  872.     NewLine( pp, hite );
  873.     siz = getStringHandleSize( theText );
  874.  
  875.     just        = pp->curntStyle.Just;
  876.     theMargin    = pp->margin.right - pp->margin.left;
  877.     
  878.     HLock( theText );
  879.     
  880.     nextWord = lineStart = lineEnd = *theText;
  881.     
  882.     while( *nextWord ){
  883.     
  884.         /*** loop invariant: lineEnd >= lineStart */
  885.         nextWord = EndOfWord( lineEnd, &hardline );
  886.         wordWidth = TextWidth( lineEnd, 0, (short)((long)nextWord-(long)lineEnd) );
  887.  
  888.         if( wordWidth + lineWidth <= theMargin )
  889.             lineWidth    += wordWidth;
  890.         else{
  891.             wid = (short)((long)lineEnd - (long)lineStart);
  892.             FlushLine(pp, lineStart,wid,just,theLeft,theRight,hite);
  893.             lineWidth = wordWidth;
  894.             lineStart = lineEnd;
  895.         }
  896.         
  897.         if( hardline ){
  898.             lineEnd = nextWord;
  899.             wid = (short)((long)lineEnd - (long)lineStart);
  900.             FlushLine( pp, lineStart, wid, just, theLeft, theRight, hite);
  901.             lineWidth = 0;
  902.             lineStart = lineEnd;
  903.             /*CheckPageBreak( pp, hite );
  904.             NewLine( pp, hite );
  905.             */
  906.         }
  907.         
  908.         lineEnd = nextWord;
  909.         
  910.     }/* while( *nextword ) */
  911.  
  912.     /*** whatever is left in the buffer will fit on one line    ***/
  913.     FlushLine( pp,lineStart,(short)(lineEnd-lineStart),just,theLeft,theRight,hite);
  914.     
  915.     HUnlock( theText );    
  916.     SetPort( oldPort );
  917. }
  918.  
  919.  
  920.  
  921.  
  922.  
  923.  
  924.  
  925.